home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / advanced97 / chromakey_fancy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  7.6 KB  |  326 lines

  1. #include <assert.h>
  2. #include <math.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <GL/glut.h>
  6. #include "texture.h"
  7.  
  8. static char defaultFile0[] = "data/swamp.rgb";
  9. static char defaultFile1[] = "data/swamp.rgb";
  10. static char defaultFile2[] = "data/mandrill256.rgb";
  11. GLuint *img0, *img1, *img2;
  12. GLsizei w, h;
  13. GLsizei w0, w1, w2, h0, h1, h2;
  14. GLint comp;
  15. GLfloat key[3] = {0, 0, 0};
  16.  
  17. #define RW 0.3086
  18. #define GW 0.6094
  19. #define BW 0.0820
  20.  
  21. /* key values less than or equal to lower fudge map to totally 
  22.  * transparent... */
  23. GLfloat lowerfudge = .2; 
  24. GLfloat upperfudge = .8;
  25.  
  26. void init(void)
  27. {
  28. }
  29.  
  30. GLuint *load_img(const char *fname, GLsizei *imgW, GLsizei *imgH)
  31. {
  32.   GLuint *img;
  33.  
  34.   img = read_texture(fname, imgW, imgH, &comp);
  35.   if (!img) {
  36.     fprintf(stderr, "Could not open %s\n", fname);
  37.     exit(1);
  38.   }
  39.  
  40.   return img;
  41. }
  42.  
  43. GLuint *
  44. resize_img(GLuint *img, GLsizei curW, GLsizei curH)
  45. {
  46.  
  47.   glPixelZoom((float)w / (float)curW, (float)h / (float)curH);
  48.   glRasterPos2i(0, 0);
  49.   glDrawPixels(curW, curH, GL_RGBA, GL_UNSIGNED_BYTE, img);
  50.   free(img);
  51.   img = (GLuint *)malloc(w * h * sizeof(GLuint));
  52.   if (!img) {
  53.     fprintf(stderr, "Malloc of %d bytes failed.\n", 
  54.         curW * curH * sizeof(GLuint));
  55.     exit(1);
  56.   }
  57.   glPixelZoom(1, 1);
  58.   glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img);
  59.  
  60.   return img;
  61. }
  62.  
  63. void reshape(GLsizei winW, GLsizei winH) 
  64. {
  65.     glViewport(0, 0, 2*w, 2*h);
  66.     glLoadIdentity();
  67.     glOrtho(0, 2*w, 0, 2*h, 0, 5);
  68. }
  69.  
  70. void compute_matte(void)
  71. {
  72.   glClear(GL_ACCUM_BUFFER_BIT);
  73.  
  74.   /* draw rectangle in (key color + 1) / 2 */
  75.   glBegin(GL_QUADS);
  76.   glColor3f(key[0], key[1], key[2]);
  77.   glVertex2f(0, 0);
  78.   glVertex2f(w, 0);
  79.   glVertex2f(w, h);
  80.   glVertex2f(0, h);
  81.   glEnd();
  82.   glFlush();
  83.  
  84.   /* negate & accumulate  */
  85.   glAccum(GL_LOAD, -1);
  86.  
  87.   /* compute & return (image - key) */
  88.   glRasterPos2f(0, 0);
  89.   glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, img0);
  90.   glAccum(GL_ACCUM, 1);
  91.   glAccum(GL_RETURN, 1);
  92.  
  93.   /* move to right hand side of window */
  94.   glRasterPos2f(w, 0);
  95.   glCopyPixels(0, 0, w, h, GL_COLOR);
  96.  
  97.   /* compute & return (key - image) */
  98.   glEnable(GL_SCISSOR_TEST);
  99.   glScissor(0, 0, w, h);
  100.   glAccum(GL_MULT, -1);
  101.   glAccum(GL_RETURN, 1);
  102.   glScissor(0, 0, 2*w, h);
  103.   glDisable(GL_SCISSOR_TEST);
  104.  
  105.   /* assemble to get fabs(key - image) */
  106.   glBlendFunc(GL_ONE, GL_ONE);
  107.   glEnable(GL_BLEND);
  108.   glRasterPos2i(0, 0);
  109.   glCopyPixels(w, 0, w, h, GL_COLOR);
  110.   glDisable(GL_BLEND);
  111.  
  112.   /* assemble into alpha channel */
  113.   {
  114.     GLfloat mat[] = {
  115.       RW, RW, RW, RW,
  116.       GW, GW, GW, GW,
  117.       BW, BW, BW, BW,
  118.       0, 0, 0, 0,
  119.     };
  120.     glMatrixMode(GL_COLOR);
  121.     glLoadMatrixf(mat);
  122.  
  123.     glRasterPos2i(w, 0);
  124.     glCopyPixels(0, 0, w, h, GL_COLOR);
  125.     glLoadIdentity();
  126.     glMatrixMode(GL_MODELVIEW);
  127.  
  128.     /* do a second copy because sbias comes after color matrix in the
  129.      * transfer pipeline.  could avoid this by using the post color matrix
  130.      * scale bias... */
  131.     if (upperfudge - lowerfudge) {
  132.       glPixelTransferf(GL_ALPHA_SCALE, 1./(upperfudge - lowerfudge));
  133.       glPixelTransferf(GL_ALPHA_BIAS, -lowerfudge/(upperfudge - lowerfudge)); 
  134.     } else {
  135.       /* move such that upper/lowerfudge maps to .5, then quantize with
  136.        * 2-entry pixel map. */
  137.       GLushort quantize[] = {0, 0xffff};
  138.       glPixelTransferf(GL_ALPHA_BIAS, .5 - upperfudge);
  139.       glPixelMapusv(GL_PIXEL_MAP_A_TO_A, 2, quantize);
  140.       glPixelTransferi(GL_MAP_COLOR, 1);
  141.     }
  142.     glRasterPos2i(w, 0);
  143.     glCopyPixels(w, 0, w, h, GL_COLOR);
  144.     glPixelTransferf(GL_ALPHA_SCALE,  1);
  145.     glPixelTransferf(GL_ALPHA_BIAS, 0);
  146.     glPixelTransferi(GL_MAP_COLOR, 0);
  147.   }
  148.  
  149.  
  150.   /* copy matte to right */
  151.   glRasterPos2i(0, 0);
  152.   glCopyPixels(w, 0, w, h, GL_COLOR);
  153.  
  154.   /* draw the third image */
  155.   glColorMask(1, 1, 1, 0);
  156.   glRasterPos2i(w, 0);
  157.   glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, img2);
  158.   glColorMask(1, 1, 1, 1);
  159.  
  160.   glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
  161.   glEnable(GL_BLEND);
  162.   glRasterPos2i(w, 0);
  163.   glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, img1);
  164.  
  165.   /* this is for matte display... */
  166.   glColor3f(1, 1, 1);
  167.   glBegin(GL_QUADS);
  168.   glVertex2f(0, 0);
  169.   glVertex2f(w, 0);
  170.   glVertex2f(w, h);
  171.   glVertex2f(0, h);
  172.   glEnd();
  173.  
  174.   glDisable(GL_BLEND);
  175. }
  176.  
  177. void draw(void)
  178. {
  179.   GLenum err;
  180.   static int first = 1;
  181.   
  182.   if (first) {
  183.     printf("Scaling images to %d by %d\n", w, h);
  184.  
  185.  
  186.     if (w0 != w || h0 != h) {
  187.       img0 = resize_img(img0, w0, h0);
  188.  
  189.     }
  190.     if (w1 != w || h1 != h) {
  191.       img1 = resize_img(img1, w1, h1);
  192.     }
  193.     if (w2 != w || h2 != h) {
  194.       img2 = resize_img(img2, w2, h2);
  195.     }
  196.     first = 0;
  197.   }
  198.   
  199.   
  200.   glClear(GL_COLOR_BUFFER_BIT);
  201.   compute_matte();
  202.   
  203.   glRasterPos2i(w/2, h);
  204.   glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, img0);
  205.  
  206.   err = glGetError();
  207.   if (err != GL_NO_ERROR) printf("Error:  %s\n", gluErrorString(err));
  208. }
  209.  
  210. /* ARGSUSED */
  211. void button(int button, int state, int xpos, int ypos)
  212. {
  213.   if (state != GLUT_UP) return;
  214.  
  215.   ypos = 2*h - ypos;
  216.   glReadPixels(xpos, ypos, 1, 1, GL_RGB, GL_FLOAT, key);
  217.   printf("Key is (%f %f %f)\n", key[0], key[1], key[2]);
  218.   draw();
  219. }
  220.  
  221. /* ARGSUSED1 */
  222. void keyPress(unsigned char whichKey, int x, int y)
  223. {
  224.   if (whichKey == 27) exit(0);
  225. }
  226.  
  227. void change_lower_fudge(int val)
  228. {
  229.   lowerfudge = (float)val / 100.;
  230.   if (upperfudge < lowerfudge) upperfudge = lowerfudge;
  231.   draw();
  232. }
  233.  
  234. void change_upper_fudge(int val)
  235. {
  236.   upperfudge = (float)val / 100.;
  237.   if (lowerfudge > upperfudge) lowerfudge = upperfudge;
  238.   draw();
  239. }
  240.  
  241. void show_usage(void) 
  242. {
  243.   fprintf(stderr, "Usage:\n");
  244.   fprintf(stderr, "chromakey mattefile file0 file1 [matteR matteG matteB]\n");
  245.   fprintf(stderr, "chromakey mattefileAndfile0 file1 [matteR matteG matteB]\n");
  246. }
  247.  
  248. main(int argc, char *argv[])
  249. {
  250.   char *fileName0 = defaultFile0, *fileName1 = defaultFile1, 
  251.   *fileName2 = defaultFile2;
  252.   
  253.   glutInit(&argc, argv);
  254.   if (argc > 1) {
  255.     fileName0 = fileName1 = argv[1];
  256.   }
  257.   if (argc > 2) {
  258.     fileName2 = argv[2];
  259.   }
  260.   if (argc > 3) {
  261.     fileName1 = fileName2;
  262.     fileName2 = argv[3];
  263.   }
  264.   if (argc > 4) {
  265.     if (argc == 6 || argc == 7) {
  266.       key[0] = atof(argv[argc-3]);
  267.       key[1] = atof(argv[argc-2]);
  268.       key[2] = atof(argv[argc-1]);
  269.     } else {
  270.       show_usage();
  271.       exit(1);
  272.     }
  273.   }
  274.   
  275.   printf("Matte file is %s\n", fileName0);
  276.   printf("Image file 1 is %s\n", fileName1);
  277.   printf("Image file 2 is %s\n", fileName2);
  278.   printf("Key is (%f %f %f)\n", key[0], key[1], key[2]);
  279.   printf("Transparent boundary is %f\n", lowerfudge);
  280.   printf("Opaque boundary is %f\n", upperfudge);
  281.   img0 = load_img(fileName0, &w0, &h0);
  282.   img1 = load_img(fileName1, &w1, &h1);
  283.   img2 = load_img(fileName2, &w2, &h2);
  284.   
  285. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  286.   w = MAX(MAX(w0, w1), w2);
  287.   h = MAX(MAX(h0, h1), h2);
  288.   
  289.   glutInitWindowSize(2*w, 2*h);
  290.   glutInitWindowPosition(0, 0);
  291.   glutInitDisplayMode(GLUT_RGBA | GLUT_ACCUM | GLUT_ALPHA);
  292.   glutCreateWindow(argv[0]);
  293.   glutDisplayFunc(draw);
  294.   glutKeyboardFunc(keyPress);
  295.   glutReshapeFunc(reshape);
  296.   glutMouseFunc(button);
  297.  
  298.   {
  299.     int lowerFudgeMenu, upperFudgeMenu;
  300.     lowerFudgeMenu = glutCreateMenu(change_lower_fudge);
  301.     glutAddMenuEntry("0", 0);
  302.     glutAddMenuEntry(".1", 20);
  303.     glutAddMenuEntry(".25", 20);
  304.     glutAddMenuEntry(".5", 50);
  305.     glutAddMenuEntry(".75", 75);
  306.     upperFudgeMenu = glutCreateMenu(change_upper_fudge);
  307.     glutAddMenuEntry(".25", 20);
  308.     glutAddMenuEntry(".5", 50);
  309.     glutAddMenuEntry(".75", 75);    
  310.     glutAddMenuEntry(".9", 90);
  311.     glutAddMenuEntry("1", 100);
  312.     glutCreateMenu(0);
  313.     glutAddSubMenu("Transparent boundary", lowerFudgeMenu);
  314.     glutAddSubMenu("Opaque boundary", upperFudgeMenu);
  315.     glutAttachMenu(GLUT_RIGHT_BUTTON);
  316.   }
  317.  
  318.   init();
  319.   
  320.   reshape(w, h);
  321.   glutMainLoop();
  322.   return 0;
  323. }
  324.  
  325.  
  326.